package ClassificationAlgorithm;

import Definitions.GraphClass;
import Global.ConstantVariable;
import Global.GlobalClass;
import LocalClassifier.LocalClassifierInterface;
import Result.EvaluationClass;
import Result.ResultClass;
import Result.ResultClassListClass;
import Result.ResultIdentificationClass;
import Sampling.SamplingAbstractClass;
import Sampling.SamplingFactory;
import Sampling.SamplingTests;

/*****************************************************************
* Class Name:	CO 
* Aim: 				Test the Content Only  with given parameters
* Algorithms: CO
*****************************************************************/
public class ContentOnlyClass extends CCAClass {
	
	public ContentOnlyClass(GraphClass graph, GlobalClass global,LocalClassifierInterface localClassifier, String name) 
	{
		super(graph, global,localClassifier, name);
		// TODO Auto-generated constructor stub
	}

	/*****************************************************************
	* Function Name:			Classifier   
	* Aim: 						To work the CO algorithms with the given parameters
	* Inputs:
	*  				
	* Graph g:					defines which graph is used while CCA
	*int lamda					defines the lamda value that will be used in LRTrain
	* Outputs:
	* CCA algorithm is processed on the graph. 
	*  
	* Data Structures:
	* Graph
	* Node
	*  
	* Algorithms:
	* Local Classifier
	* Neighbourhood Functions 
	*****************************************************************/
	
	public void Run(SamplingAbstractClass currentSampling, ResultClass result) 
	{
		System.out.println("Content Only: ");
		
		//EvaluationClass Evaluation = new EvaluationClass(currentSampling); 
		localClassifierSelected.initialize(graph, result);
		localClassifierSelected.train(graph);


		//TODO Kadriye : Arrange/File Organization.
		System.out.print("Result Train:");
		
		
		//First label assignments to test dataset
		for(int i=0; i< currentSampling.getTestNodes().size() ;i++)
		{
			localClassifierSelected.evaluate(currentSampling.getTestNodes().get(i), ConstantVariable.Sampling_Constants.NODE_IS_IN_TEST_SET_FOR_THE_FOLD, ConstantVariable.LocalClassifier_Constants.SOFT);
			//System.out.println(currentSampling.getTestNodes().get(i).getClassOrder() +"  " + currentSampling.getTestNodes().get(i).getPredictClassOrder() );
		}
		result.getEvaluationResult().createConfMatAndPrepareTheResults();
		//System.out.println("Content Only:   "+ Evaluation.findTotalAccuracy(Evaluation.CreateConfMat(currentSampling.getTestNodes())));
		
		for(int i=0; i< currentSampling.getTrainNodes().size() ;i++)
		{
			localClassifierSelected.evaluate(currentSampling.getTrainNodes().get(i), ConstantVariable.Sampling_Constants.NODE_IS_IN_TEST_SET_FOR_THE_FOLD, ConstantVariable.LocalClassifier_Constants.SOFT);
			//System.out.println( currentSampling.getTestNodes().get(i).getClassOrder() +"  " + currentSampling.getTestNodes().get(i).getPredictClassOrder() );
		}
		EvaluationClass eval =new EvaluationClass(currentSampling);
		double r = eval.findTotalAccuracy( eval.CreateConfMat( currentSampling.getTrainNodes()));
		System.out.print("Result Trian:"+r);
		
		result.setAccuracy(r);
	}
	
	public static void TestInParallel(GraphClass graph, GlobalClass global,LocalClassifierInterface classifier ,int numberOfFolds)
	{
		ContentOnlyClass ContentOnlyClassifier;
		
		ContentOnlyClassifier = new ContentOnlyClass(graph, global, classifier, ConstantVariable.CCA_ConstantVariables.CONTENT_ONLY);
		
		ContentOnlyTestProcessorThreadClass[] ContentOnlyTestProcessorPool;
		
		System.out.println("Content Only Test Start ");
				
		int numberOfCores;
		
		int numberOfCompletedFolds=0;
		int numberOfNeededThreads=0;
		
		numberOfCores = GlobalClass.RunningValues.maximumNumberOfCPUCoresToBeUsedForTooMuchRamRequiringAndTimeConsumingTasks;
		ContentOnlyTestProcessorPool = new ContentOnlyTestProcessorThreadClass[numberOfCores];
		
		if(numberOfFolds < numberOfCores)
			numberOfNeededThreads = numberOfFolds;
		else
			numberOfNeededThreads = numberOfCores;
			
		String datasetName = ConstantVariable.DataSet_Constants.DATASET_NAMES[GlobalClass.RunningValues.executionFor];
		String CCA_Name = ConstantVariable.CCA_ConstantVariables.CONTENT_ONLY;
		String samplingName = ConstantVariable.Sampling_Constants.SNOWBALL_SAMPLING_METHOD;
			
		
		while(numberOfCompletedFolds<numberOfFolds)
		{
			if(numberOfFolds-numberOfCompletedFolds<numberOfCores)
				numberOfNeededThreads = numberOfFolds-numberOfCompletedFolds;
			
					
			
			for(int i=0; i<numberOfNeededThreads; i++)
			{
				 ResultIdentificationClass identifier = new ResultIdentificationClass();
				 identifier.setDataset(datasetName);
				 identifier.setCCA(CCA_Name);
				 identifier.setSampling(samplingName);
				 identifier.setFold(i);
				 
				 ResultClass result = new ResultClass(identifier);  	
					
					
				ContentOnlyTestProcessorPool[i] = ContentOnlyClassifier.new ContentOnlyTestProcessorThreadClass(numberOfCompletedFolds+i, graph, global, result);
				ContentOnlyTestProcessorPool[i].start();		
			}
			
			for(int i=0; i<numberOfNeededThreads; i++)
			{				
				try
				{
					ContentOnlyTestProcessorPool[i].join();
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}	
			}			
			numberOfCompletedFolds +=numberOfNeededThreads;
		}		
	}
	
	private class ContentOnlyTestProcessorThreadClass extends Thread
    {
        int index;     
        GraphClass graph;
        GlobalClass global;
        ResultClass result;
        
         
        ContentOnlyTestProcessorThreadClass(int index, GraphClass graph, GlobalClass global, ResultClass result)
        {
             this.index = index;
             this.graph = graph;
             this.global = global;
             this.result = result;
        }        
        
        public void run() 
        {
        	SamplingFactory samplingFactory = new SamplingFactory();
    		
    		SamplingAbstractClass sampling=samplingFactory.createSampling(SamplingTests.createDummyParametresForSampling(ConstantVariable.Sampling_Constants.SNOWBALL_SAMPLING_METHOD), graph, global);
    		
    		CollectiveClassificationAlgorithmFactory CCA_Factory =new CollectiveClassificationAlgorithmFactory(graph, global);
    		CollectiveClassificationAlgorithmClass CCA = CCA_Factory.createCCA(ConstantVariable.CCA_ConstantVariables.CONTENT_ONLY, ConstantVariable.LocalClassifier_Constants.LOGISTIC_REGRESSION, sampling);
    		
        	System.out.println("Fold Processor:  " + index);
			sampling.generateSampling(graph, index);
			result.setSampling(sampling);
			CCA.Run(sampling, result);
        }        
    }
	
	public static ResultClassListClass TestWithWeka(GraphClass graph, GlobalClass global, int numberOfFolds, SamplingAbstractClass prevSampling, String localClassifierName, String secondLevelLocalClassifierName)
	{
		System.out.println("Content Only WEKA Test Start ");
		
		String datasetName =ConstantVariable.DataSet_Constants.DATASET_NAMES[GlobalClass.RunningValues.executionFor];
		String CCA_Name = ConstantVariable.CCA_ConstantVariables.CONTENT_ONLY;
		String samplingName = ConstantVariable.Sampling_Constants.SNOWBALL_SAMPLING_METHOD;
		
		if(localClassifierName==null)
			localClassifierName = ConstantVariable.WekaClassifiers.GENERIC_WEKA_CLASSIFIER; 

		ResultClassListClass resultsList = new ResultClassListClass();
		
		SamplingAbstractClass sampling;
				
		if(prevSampling==null)
		{
			SamplingFactory samplingFactory = new SamplingFactory();
		
			sampling=samplingFactory.createSampling(SamplingTests.createDummyParametresForSampling(samplingName), graph, global);
		}
		else
			sampling = prevSampling;
						
		CollectiveClassificationAlgorithmFactory CCA_Factory =new CollectiveClassificationAlgorithmFactory(graph, global);
		CollectiveClassificationAlgorithmClass CCA = CCA_Factory.createCCA(ConstantVariable.CCA_ConstantVariables.CONTENT_ONLY, localClassifierName, sampling);		
		CCA.getLocalClassifierSelected().changeSecondLevelClassifierToBeUsed(secondLevelLocalClassifierName);
			
		
	    for(int i=0;  i<numberOfFolds ;i++)
		{
	    	ResultIdentificationClass identifier = new ResultIdentificationClass();
	    	identifier.setDataset(datasetName);
	    	identifier.setCCA(CCA_Name);
	    	identifier.setSampling(samplingName);
	    	identifier.setFold(i);

	    	ResultClass result = new ResultClass(identifier);
	    	System.out.println("Fold :  " + i);
	    	if(prevSampling==null)			
	    		sampling.generateSampling(graph,i);
	    	result.setSampling(sampling);
	    	CCA.Run(sampling, result);
	    	resultsList.addToResultsList(result);
		}
		return resultsList;
	}

	// Samplingi dolu getir..
	public static ResultClassListClass TestWithWekaInParallelStart(GraphClass graph, GlobalClass global, int numberOfFolds, SamplingAbstractClass prevSampling, String localClassifierName, String secondLevelLocalClassifierName)
	{
		CollectiveClassificationAlgorithmFactory CCA_Factory =new CollectiveClassificationAlgorithmFactory(graph, global);
		CollectiveClassificationAlgorithmClass CCA = CCA_Factory.createCCA(ConstantVariable.CCA_ConstantVariables.CONTENT_ONLY, localClassifierName, null);
		return ((ContentOnlyClass)CCA).TestWithWekaInParallel(graph, global, numberOfFolds, prevSampling, localClassifierName, secondLevelLocalClassifierName);
	}
	
	public ResultClassListClass TestWithWekaInParallel(GraphClass graph, GlobalClass global, int numberOfFolds, SamplingAbstractClass prevSampling, String localClassifierName, String secondLevelLocalClassifierName)
	{		
		
		ContentOnlyTestWithWekaProcessorThreadClass[] ContentOnlyTestWithWekaProcessorPool;
		
		System.out.println("Content Only Test Start ");
				
		int numberOfCores;
		
		int numberOfCompletedFolds=0;
		int numberOfNeededThreads=0;
		
		numberOfCores = GlobalClass.RunningValues.maximumNumberOfCPUCoresToBeUsedForTooMuchRamRequiringAndTimeConsumingTasks;
		ContentOnlyTestWithWekaProcessorPool = new ContentOnlyTestWithWekaProcessorThreadClass[numberOfCores];
		
		if(numberOfFolds < numberOfCores)
			numberOfNeededThreads = numberOfFolds;
		else
			numberOfNeededThreads = numberOfCores;
			
		String datasetName =ConstantVariable.DataSet_Constants.DATASET_NAMES[GlobalClass.RunningValues.executionFor];
		String CCA_Name = ConstantVariable.CCA_ConstantVariables.CONTENT_ONLY;
		String samplingName = ConstantVariable.Sampling_Constants.SNOWBALL_SAMPLING_METHOD;
		
		ResultClassListClass resultsList = new ResultClassListClass();			
		
		while(numberOfCompletedFolds<numberOfFolds)
		{
			if(numberOfFolds-numberOfCompletedFolds<numberOfCores)
				numberOfNeededThreads = numberOfFolds-numberOfCompletedFolds;
			
			for(int i=0; i<numberOfNeededThreads; i++)
			{
				 ResultIdentificationClass identifier = new ResultIdentificationClass();
				 identifier.setDataset(datasetName);
				 identifier.setCCA(CCA_Name);
				 identifier.setSampling(samplingName);
				 identifier.setFold(i);
				 
				 ResultClass result = new ResultClass(identifier);
				 resultsList.addToResultsList(result);
					
				 ContentOnlyTestWithWekaProcessorPool[i] = new ContentOnlyTestWithWekaProcessorThreadClass(numberOfCompletedFolds+i, graph, global, result, localClassifierName, secondLevelLocalClassifierName, prevSampling);
				 
//				 ContentOnlyTestWithWekaProcessorPool[i] = new ContentOnlyTestWithWekaProcessorThreadClass(numberOfCompletedFolds+i, graph, global, result, localClassifierName, secondLevelLocalClassifierName);
				 ContentOnlyTestWithWekaProcessorPool[i].start();		
			}
			
			for(int i=0; i<numberOfNeededThreads; i++)
			{				
				try
				{
					ContentOnlyTestWithWekaProcessorPool[i].join();
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}	
			}			
			numberOfCompletedFolds +=numberOfNeededThreads;
		}		
		return resultsList;
	}
	
	private class ContentOnlyTestWithWekaProcessorThreadClass extends Thread
    {
        int index;     
        GraphClass graph;
        GlobalClass global;
        ResultClass result;
        String localClassifierName;
        String secondLevelLocalClassifierName;
        SamplingAbstractClass sampling;
        
        ContentOnlyTestWithWekaProcessorThreadClass(int index, GraphClass graph, GlobalClass global, ResultClass result, String localClassifierName, String secondLevelLocalClassifierName, SamplingAbstractClass  sampling)
        {
        	  this.index = index;
              this.graph = graph;
              this.global = global;
              this.result = result;
              this.localClassifierName = localClassifierName; 
              this.secondLevelLocalClassifierName = secondLevelLocalClassifierName;
              this.sampling = sampling;
        }
         
        ContentOnlyTestWithWekaProcessorThreadClass(int index, GraphClass graph, GlobalClass global, ResultClass result, String localClassifierName, String secondLevelLocalClassifierName)
        {
             this.index = index;
             this.graph = graph;
             this.global = global;
             this.result = result;
             this.localClassifierName = localClassifierName; 
             this.secondLevelLocalClassifierName = secondLevelLocalClassifierName;
        }        
        
        public void run() 
        {
    		CollectiveClassificationAlgorithmFactory CCA_Factory =new CollectiveClassificationAlgorithmFactory(graph, global);
    		CollectiveClassificationAlgorithmClass CCA = CCA_Factory.createCCA(ConstantVariable.CCA_ConstantVariables.CONTENT_ONLY, localClassifierName, sampling);
    		CCA.getLocalClassifierSelected().changeSecondLevelClassifierToBeUsed(secondLevelLocalClassifierName);
        	System.out.println("Fold Processor:  " + index);
			sampling.generateSampling(graph, index);	
			result.setSampling(sampling);
			CCA.Run(sampling, result);			
        }        
    }

	@Override
	public void initialize() {
	}

	@Override
	public void Prepare() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public ResultClass TestAlgorithm() {
		return null;
	}

	@Override
	public void report() {
		
	}
}

	